// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#pragma once

#include "ExternalObjectReference_partial.h"
#include "WeakReferenceSource.h"
#include "DependencyObject.h"
#include "ComObject.h"
#include "collectionbase.h" // uses CCollection
#include "VectorChangedEventArgs_Partial.h"
#include "BoxerBuffer.h"
#include "CoreImports.h"

#pragma warning(disable:4267) //'var' : conversion from 'size_t' to 'type', possible loss of data

#pragma region Internal Type Forward Declarations
// These are all declared to allow us to operate on internal collections of the following types.
// These specializations are typically generated by the MIDL compiler when it encounters the metadata
// for the collection type, but because these types are never exposed in metadata in order to create
// complete declarations for the various parameterized types we explicitly specialize them here.
//
// These types are dependent on the PresentationFrameworkCollection / WinRT interfaces in the first
// place because they are defined using CodeGen and we likely wanted to leverage all the implementation
// details that have been baked into these classes over the years.
namespace DirectUI
{
    class ParametricCurve;
    class ParametricCurveSegment;
    class PointerKeyFrame;
    struct TextRange;
}

XAML_ABI_NAMESPACE_BEGIN namespace Windows {
    namespace Foundation {
        namespace Collections {
            template <> struct __declspec(uuid("d942ae18-8c98-4226-a495-0d437714f974")) wfc::IIterator<DirectUI::ParametricCurve*> : IIterator_impl<wf::Internal::AggregateType<DirectUI::ParametricCurve*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("e89608f7-3d4e-4e82-b5d8-19e550976705")) wfc::IIterable<DirectUI::ParametricCurve*> : IIterable_impl<wf::Internal::AggregateType<DirectUI::ParametricCurve*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("852b656f-4e8a-495b-96b9-7fe9ed5f2934")) wfc::IVector<DirectUI::ParametricCurve*> : IVector_impl<wf::Internal::AggregateType<DirectUI::ParametricCurve*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("ef1cab62-8115-4bb3-86df-71d98d3b7af0")) wfc::IVectorView<DirectUI::ParametricCurve*> : IVectorView_impl<wf::Internal::AggregateType<DirectUI::ParametricCurve*, xaml::IDependencyObject*>>{};

            template <> struct __declspec(uuid("41164128-aa45-469c-92c9-b2c8c2f3b30b")) wfc::IIterator<DirectUI::ParametricCurveSegment*> : IIterator_impl<wf::Internal::AggregateType<DirectUI::ParametricCurveSegment*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("cea6ffea-78a3-45a0-b30a-6a0b0ccd6359")) wfc::IIterable<DirectUI::ParametricCurveSegment*> : IIterable_impl<wf::Internal::AggregateType<DirectUI::ParametricCurveSegment*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("bd6681c2-837c-4352-b510-2ac082281e0a")) wfc::IVector<DirectUI::ParametricCurveSegment*> : IVector_impl<wf::Internal::AggregateType<DirectUI::ParametricCurveSegment*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("2c43b768-5365-4122-8429-fa922d1d5654")) wfc::IVectorView<DirectUI::ParametricCurveSegment*> : IVectorView_impl<wf::Internal::AggregateType<DirectUI::ParametricCurveSegment*, xaml::IDependencyObject*>>{};

            template <> struct __declspec(uuid("02a8a3df-51e0-484f-aa37-b079c37b9591")) wfc::IIterator<DirectUI::PointerKeyFrame*> : IIterator_impl<wf::Internal::AggregateType<DirectUI::PointerKeyFrame*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("c5c39ebe-95f7-4364-900e-bbd21069ce97")) wfc::IIterable<DirectUI::PointerKeyFrame*> : IIterable_impl<wf::Internal::AggregateType<DirectUI::PointerKeyFrame*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("23cdcc52-6b38-447a-b06b-fa514feddc8f")) wfc::IVector<DirectUI::PointerKeyFrame*> : IVector_impl<wf::Internal::AggregateType<DirectUI::PointerKeyFrame*, xaml::IDependencyObject*>>{};
            template <> struct __declspec(uuid("1068d4e7-0e8f-42e2-adcb-9270207cfc0c")) wfc::IVectorView<DirectUI::PointerKeyFrame*> : IVectorView_impl<wf::Internal::AggregateType<DirectUI::PointerKeyFrame*, xaml::IDependencyObject*>>{};

            template <> struct __declspec(uuid("e6c3bd6f-5331-4b5e-a64f-766c7068bfc6")) wfc::IIterator<xaml::Internal::SecondaryContentRelationship*> : IIterator_impl<wf::Internal::AggregateType<xaml::Internal::SecondaryContentRelationship*, xaml::Internal::ISecondaryContentRelationship*>>{};
            template <> struct __declspec(uuid("b9a03a27-c9d6-459d-a8f7-49dc603e1d30")) wfc::IIterable<xaml::Internal::SecondaryContentRelationship*> : IIterable_impl<wf::Internal::AggregateType<xaml::Internal::SecondaryContentRelationship*, xaml::Internal::ISecondaryContentRelationship*>>{};
            template <> struct __declspec(uuid("dda0c481-23cb-43b8-9d47-d26cc14f4273")) wfc::IVector<xaml::Internal::SecondaryContentRelationship*> : IVector_impl<wf::Internal::AggregateType<xaml::Internal::SecondaryContentRelationship*, xaml::Internal::ISecondaryContentRelationship*>>{};
            template <> struct __declspec(uuid("b4dfa332-2be4-4346-9c5b-5f06cf699fcd")) wfc::IVectorView<xaml::Internal::SecondaryContentRelationship*> : IVectorView_impl<wf::Internal::AggregateType<xaml::Internal::SecondaryContentRelationship*, xaml::Internal::ISecondaryContentRelationship*>>{};
        }

        inline bool operator==(const DateTime& lhs, const DateTime& rhs)
        {
            return lhs.UniversalTime == rhs.UniversalTime;
        }
    }
} XAML_ABI_NAMESPACE_END
#pragma endregion

namespace DirectUI
{

#pragma region Iterator
    // FUTURE: Could we just use the WRL implementations here?
    template <class T>
    class __declspec(novtable) IteratorBase :
        public wfc::IIterator<T>,
        public ctl::WeakReferenceSource
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IIterator<T>::T_complex>::type T_abi;

        BEGIN_INTERFACE_MAP(IteratorBase, ctl::WeakReferenceSource)
            INTERFACE_ENTRY(IteratorBase, wfc::IIterator<T>)
        END_INTERFACE_MAP(IteratorBase, ctl::WeakReferenceSource)

    public:
        _Check_return_ HRESULT SetView(_In_ wfc::IVectorView<T>* pView)
        {
            IFCPTR_RETURN(pView);
            SetPtrValue(m_tpView, pView);
            BOOLEAN bHasCurrent;
            IFC_RETURN(MoveNext(&bHasCurrent));
            return S_OK;
        }

        IFACEMETHODIMP get_Current(_Out_ T_abi *current) override
        {
            IFC_RETURN(CheckThread());
            IFCPTR_RETURN(current);
            IFCEXPECT_RETURN(m_nCurrentIndex > 0);
            IFC_RETURN(GetCurrent(current));
            return S_OK;
        }

        IFACEMETHODIMP get_HasCurrent(_Out_ BOOLEAN *hasCurrent) override
        {
            IFC_RETURN(CheckThread());
            IFCPTR_RETURN(hasCurrent);

            unsigned nSize;
            IFC_RETURN(m_tpView->get_Size(&nSize));
            *hasCurrent = (m_nCurrentIndex > 0 && m_nCurrentIndex <= nSize);
            return S_OK;
        }

        IFACEMETHODIMP MoveNext(_Out_ BOOLEAN *hasCurrent) override
        {
            unsigned nSize;

            IFC_RETURN(CheckThread());
            IFCPTR_RETURN(hasCurrent);
            IFC_RETURN(m_tpView->get_Size(&nSize));

            *hasCurrent = FALSE;
            ClearCurrent();
            if (m_nCurrentIndex >= 0 && m_nCurrentIndex < nSize)
            {
                // This is really dodgy- this can be either an IInspectable or
                // a standard value type. We rely on SetCurrent assuming that we've
                // passed ownership for ref-counting to work correctly.
                T_abi current;
                IFC_RETURN(m_tpView->GetAt(m_nCurrentIndex, &current));
                SetCurrent(current);
                m_nCurrentIndex++;
                *hasCurrent = TRUE;
            }
            else
            {
                // Use this as a marker that we're done, this will make it so
                // HasCurrent will also return false
                m_nCurrentIndex = nSize + 1;
            }
            return S_OK;
        }

    protected:
        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IIterator<T>)))
            {
                *ppObject = static_cast<wfc::IIterator<T> *>(this);
            }
            else
            {
                return ctl::WeakReferenceSource::QueryInterfaceImpl(iid, ppObject);
            }

            AddRefOuter();
            return S_OK;
        }

        // This class is marked novtable, so must not be instantiated directly.
        IteratorBase()
            : m_nCurrentIndex(0)
        {
        }

        ~IteratorBase() override
        {
            IsDebuggerPresent();
        }

        virtual _Check_return_ HRESULT GetCurrent(_Out_ T_abi *current) = 0;
        virtual void SetCurrent(_In_ T_abi current) = 0;
        virtual void ClearCurrent() {};

        _Check_return_ HRESULT Initialize() override
        {
            IFC_RETURN(WeakReferenceSource::Initialize());
            return S_OK;
        }

    private:
        TrackerPtr<wfc::IVectorView<T>> m_tpView;
        unsigned int m_nCurrentIndex;
    };

    template <class T>
    class __declspec(novtable) Iterator
        : public IteratorBase<T>
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IIterator<T>::T_complex>::type T_abi;
        typedef typename std::remove_pointer<T_abi>::type T_abi_ptrRemoved;

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        Iterator() = default;

        _Check_return_ HRESULT GetCurrent(_Out_ T_abi *current) override
        {
            IFCPTR_RETURN(current);
            *current = m_current.Get();
            AddRefInterface(m_current.Get());
            return S_OK;
        }

        void ClearCurrent() override
        {
            m_current.Clear();
        }

        void SetCurrent(_In_ T_abi current) override
        {
            IteratorBase<T>::SetPtrValue(m_current, current);

            // Danger Will Robinson, Danger! Dodgy ownership semantics head...
            ReleaseInterface(current);
        }

        TrackerPtr<T_abi_ptrRemoved> m_current{};
    };

    template<>
    class Iterator<FLOAT>
        : public IteratorBase<FLOAT>
    {
    protected:
        _Check_return_ HRESULT GetCurrent(_Out_ FLOAT *current) override
        {
            IFCPTR_RETURN(current);
            *current = m_current;
            return S_OK;
        }

        void SetCurrent(_In_ FLOAT current) override
        {
            m_current = current;
        }

    private:
        FLOAT m_current{};
    };

    template<>
    class Iterator<DOUBLE>
        : public IteratorBase<DOUBLE>
    {
    protected:
        _Check_return_ HRESULT GetCurrent(_Out_ DOUBLE *current) override
        {
            IFCPTR_RETURN(current);
            *current = m_current;
            return S_OK;
        }

        void SetCurrent(_In_ DOUBLE current) override
        {
            m_current = current;
        }

    private:
        DOUBLE m_current{};
    };

    template<>
    class Iterator<wf::Point>
        : public IteratorBase<wf::Point>
    {
    protected:
        _Check_return_ HRESULT GetCurrent(_Out_ wf::Point *current) override
        {
            IFCPTR_RETURN(current);
            *current = m_current;
            return S_OK;
        }

        void SetCurrent(_In_ wf::Point current) override
        {
            m_current = current;
        }

    private:
        wf::Point m_current{};
    };


    template<>
    class Iterator<xaml_docs::TextRange>
        : public IteratorBase<xaml_docs::TextRange>
    {
    protected:
        _Check_return_ HRESULT GetCurrent(_Out_ xaml_docs::TextRange *current) override
        {
            IFCPTR_RETURN(current);
            *current = m_current;
            return S_OK;
        }

        void SetCurrent(_In_ xaml_docs::TextRange current) override
        {
            m_current = current;
        }

    private:
        xaml_docs::TextRange m_current{};
    };
#pragma endregion

#pragma region Views And Non-DO-Backed Collections
    template <class T>
    class __declspec(novtable) ViewBase:
        public wfc::IVectorView<T>,
        public wfc::IIterable<T>,
        public ctl::WeakReferenceSource
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IVector<T>::T_complex>::type T_abi;

        BEGIN_INTERFACE_MAP(ViewBase, ctl::WeakReferenceSource)
            INTERFACE_ENTRY(ViewBase, wfc::IVectorView<T>)
            INTERFACE_ENTRY(ViewBase, wfc::IIterable<T>)
        END_INTERFACE_MAP(ViewBase, ctl::WeakReferenceSource)

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ViewBase() = default;

        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IVectorView<T>)))
            {
                *ppObject = static_cast<wfc::IVectorView<T> *>(this);
            }
            else if (InlineIsEqualGUID(iid, __uuidof(wfc::IIterable<T>)))
            {
                *ppObject = static_cast<wfc::IIterable<T> *>(this);
            }
            else
            {
                RRETURN(ctl::WeakReferenceSource::QueryInterfaceImpl(iid, ppObject));
            }

            AddRefOuter();
            RRETURN(S_OK);
        }

    public:
        ~ViewBase() override
        {
            ClearView();
        }

        virtual void ClearView()
        {
            for (auto it = m_list.begin(); it != m_list.end(); ++it)
            {
                if (*it)
                {
                    (*it)->Release();
                }
            }

            m_list.clear();
        }

        _Check_return_ HRESULT SetView(_In_ wfc::IIterator<T>* view)
        {
            HRESULT hr = S_OK;
            T_abi item = NULL;

            IFCPTR(view);

            ClearView();
            BOOLEAN hasCurrent = FALSE;
            IFC(view->get_HasCurrent(&hasCurrent));
            while (hasCurrent)
            {
                IFC(view->get_Current(&item));
                m_list.push_back(item);
                item = NULL;
                IFC(view->MoveNext(&hasCurrent));
            }

        Cleanup:

            ReleaseInterface(item);

            RRETURN(hr);
        }

        IFACEMETHODIMP get_Size(_Out_ UINT *size) override
        {
            HRESULT hr = S_OK;

            IFC(CheckThread());
            *size = static_cast<UINT>(m_list.size());

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP GetAt(UINT index, _Out_ T_abi *item) override
        {
            HRESULT hr = S_OK;
            UINT nPosition = 0;

            IFC(CheckThread());

            for (auto it = m_list.begin(); it != m_list.end(); ++nPosition, ++it)
            {
                if (nPosition == index)
                {
                    *item = *it;
                    AddRefInterface(*it);
                    goto Cleanup;
                }
            }

            IFC(E_FAIL);

        Cleanup:
            RRETURN(hr);
        }

        // IIterable<T> implementation
        IFACEMETHODIMP First(_Outptr_result_maybenull_ wfc::IIterator<T> **first) override
        {
            HRESULT hr = S_OK;
            Iterator<T>* pIterator = NULL;

            IFC(CheckThread());

            IFC(ctl::ComObject<Iterator<T>>::CreateInstance(&pIterator));
            IFC(pIterator->SetView(this));
            *first = pIterator;
            pIterator = NULL;

        Cleanup:
            ctl::release_interface(pIterator);
            RRETURN(hr);
        }

    protected:
        std::list<T_abi> m_list;
    };

    template <class T>
    class __declspec(novtable) View:
        public ViewBase<T>
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IVector<T>::T_complex>::type T_abi;
    protected:
        // This class is marked novtable, so must not be instantiated directly.
        View() = default;

    public:
        IFACEMETHODIMP IndexOf(_In_opt_ T_abi value, _Out_ UINT *index, _Out_ BOOLEAN *found) override
        {
            HRESULT hr = S_OK;
            UINT nPosition = 0;

            IFC(this->CheckThread());

            for (auto it = this->m_list.begin(); it != this->m_list.end(); ++nPosition, ++it)
            {
                if (*it == value)
                {
                    *index = nPosition;
                    *found = TRUE;
                    goto Cleanup;
                }
            }

            *index = 0;
            *found = FALSE;

        Cleanup:
            RRETURN(hr);
        }
    };

    template<>
    class View<IInspectable*>:
        public ViewBase<IInspectable*>
    {
    public:
        IFACEMETHOD(IndexOf)(
            _In_opt_ IInspectable* value,
            _Out_ UINT *index,
            _Out_ BOOLEAN *found) override;
    };

    MIDL_INTERFACE("d1141e8a-d8e1-4c81-849b-35f0c231464e")
    IUntypedVector: public IInspectable
    {
        IFACEMETHOD(UntypedAppend)(_In_ IInspectable* pItem);
        IFACEMETHOD(UntypedGetSize)(_Out_ unsigned int* pSize);
        IFACEMETHOD(UntypedGetAt)(_In_ unsigned int index, _COM_Outptr_ IInspectable** ppItem);
        IFACEMETHOD(UntypedInsertAt)(_In_ unsigned int index, _In_ IInspectable* pItem);
        IFACEMETHOD(UntypedRemoveAt)(_In_ unsigned int index);
        IFACEMETHOD(UntypedClear)();
    };

    bool UntypedTryGetIndexOf(_In_ IUntypedVector* vector, _In_ IInspectable* item, _Out_ unsigned int* index);

    template <class T>
    _Check_return_ HRESULT InitializeReadOnlyCollectionFromIterable(T pCollection, IInspectable *pSource)
    {
        HRESULT hr = S_OK;
        xaml_interop::IBindableIterable *pBindableItems = NULL;
        wfc::IIterable<IInspectable *> *pItems = NULL;
        wfc::IIterator<IInspectable *> *pIterator = NULL;
        IInspectable *pItem = NULL;
        BOOLEAN hasCurrent = false;

        // Note: The source must be iterable at the very least for us to be able to do anything with it

        // If the source is not IIterable<IInspectable *> then it must be
        // IBindableIterable, otherwise is a bad source
        pItems = ctl::query_interface<wfc::IIterable<IInspectable *>>(pSource);
        if (pItems == NULL)
        {
            pBindableItems = ctl::query_interface<xaml_interop::IBindableIterable>(pSource);
            if (pBindableItems == NULL)
            {
                // The source is not bindable, so nothing to do
                goto Cleanup;
            }

            // IBindableIterable is v-table compatible with IIterable<IInspectable *>
            pItems = reinterpret_cast<wfc::IIterable<IInspectable *> *>(pBindableItems);
            pBindableItems = NULL;
        }

        IFC(pItems->First(&pIterator));
        IFC(pIterator->get_HasCurrent(&hasCurrent));
        while (hasCurrent)
        {
            IFC(pIterator->get_Current(&pItem));
            IFC(pCollection->InternalAppend(pItem));
            ReleaseInterface(pItem);
            IFC(pIterator->MoveNext(&hasCurrent));
        }

    Cleanup:
        ReleaseInterface(pBindableItems);
        ReleaseInterface(pItems);
        ReleaseInterface(pIterator);
        ReleaseInterface(pItem);
        RRETURN(hr);
    }

#pragma endregion

#pragma region DO-backed Collection
    // This guy is the really the most interesting class in this whole header file. We need a separate
    // implementation of ICollection to be able to do all of our fancy reference tracking and integrate
    // with the CLR properly, which is why we're not simply using the WRL implementations. This is the public
    // wrapper around CDOCollection, a core object full of dragons and evil, that will do the appropriate peer
    // tracking to make GC play nice with us.
    class __declspec(novtable) PresentationFrameworkCollectionBase
        : public DependencyObject
    {
    protected:
        // This class is marked novtable, so must not be instantiated directly.
        PresentationFrameworkCollectionBase() = default;
    };

    template <class T>
    class __declspec(novtable) PresentationFrameworkCollectionTemplateBase:
        public wfc::IVectorView<T>,
        public wfc::IVector<T>,
        public wfc::IIterable<T>,
        public PresentationFrameworkCollectionBase
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IVector<T>::T_complex>::type T_abi;

        BEGIN_INTERFACE_MAP(PresentationFrameworkCollectionTemplateBase, PresentationFrameworkCollectionBase)
            INTERFACE_ENTRY(PresentationFrameworkCollectionTemplateBase, wfc::IVectorView<T>)
            INTERFACE_ENTRY(PresentationFrameworkCollectionTemplateBase, wfc::IVector<T>)
            INTERFACE_ENTRY(PresentationFrameworkCollectionTemplateBase, wfc::IIterable<T>)
        END_INTERFACE_MAP(PresentationFrameworkCollectionTemplateBase, PresentationFrameworkCollectionBase)

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        PresentationFrameworkCollectionTemplateBase() = default;

        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IVectorView<T>)))
            {
                *ppObject = static_cast<wfc::IVectorView<T> *>(this);
            }
            else if (InlineIsEqualGUID(iid, __uuidof(wfc::IVector<T>)))
            {
                *ppObject = static_cast<wfc::IVector<T> *>(this);
            }
            else if (InlineIsEqualGUID(iid, __uuidof(wfc::IIterable<T>)))
            {
                *ppObject = static_cast<wfc::IIterable<T> *>(this);
            }
            else
            {
                return PresentationFrameworkCollectionBase::QueryInterfaceImpl(iid, ppObject);
            }
            AddRefOuter();
            return S_OK;
        }

    public:
        IFACEMETHODIMP get_Size(_Out_ UINT *size) override
        {
            IFC_RETURN(CheckThread());
            *size = static_cast<CCollection*>(GetHandle())->GetCount();
            return S_OK;
        }

        IFACEMETHODIMP GetView(_Outptr_result_maybenull_ wfc::IVectorView<T> **view) override
        {
            if (view)
            {
                return (ctl::do_query_interface(*view, this));
            }
            return E_NOTIMPL;
        }

        IFACEMETHODIMP SetAt(UINT index, _In_ T_abi item) override
        {
            IFC_RETURN(CheckThread());
            UINT size = 0;
            IFC_RETURN(get_Size(&size));
            IFCEXPECTRC_RETURN(index < size, E_BOUNDS);

            // Two step process to simulate setting a particular
            // position on the collection
            IFC_RETURN(this->InsertAt(index, item));
            IFC_RETURN(RemoveAt(index + 1));
            return S_OK;
        }

        IFACEMETHODIMP RemoveAt(UINT index) override
        {
            IFC_RETURN(CheckThread());

            UINT size = 0;
            IFC_RETURN(get_Size(&size));
            IFCEXPECTRC_RETURN(index < size, E_BOUNDS);

            IFC_RETURN(CoreImports::Collection_RemoveAt(static_cast<CCollection*>(GetHandle()), index));
            return S_OK;
        }

        IFACEMETHODIMP RemoveAtEnd() override
        {
            UINT size = 0;

            IFC_RETURN(CheckThread());
            IFC_RETURN(get_Size(&size));
            IFCEXPECT_RETURN(size > 0);

            IFC_RETURN(RemoveAt(size - 1));
            return S_OK;
        }

        IFACEMETHODIMP Clear() override
        {
            IFC_RETURN(CheckThread());
            IFC_RETURN(CoreImports::Collection_Clear(static_cast<CCollection*>(GetHandle())));
            return S_OK;
        }

        //  The method moves the element from "index" position to the position immediately before the element at position "position".
        //  Move (pos, pos) is NoOp
        //  Move (pos, pos+1) is NoOp
        //  To move to the end, position should be equal to elements count.
        /// <param name="index">Index of the element which should be moved</param>
        /// <param name="position">Position immediately after the element's new position</param>
        _Check_return_ HRESULT MoveInternal(_In_ UINT index, _In_ UINT position)
        {
            UINT nCount = 0;
            IFC_RETURN(get_Size(&nCount));
            IFCEXPECT_RETURN(index >= 0 && index < nCount && position >= 0 && position <= nCount);
            if (index != position && position - index != 1)
            {
                IFC_RETURN(CoreImports::Collection_Move(static_cast<CCollection*>(GetHandle()), index, position));
            }
            return S_OK;
        }

        IFACEMETHODIMP First(_Outptr_result_maybenull_ wfc::IIterator<T>** first) override
        {
            Iterator<T>* pIterator = nullptr;
            IFC_RETURN(CheckThread());
            IFC_RETURN(ctl::ComObject<Iterator<T>>::CreateInstance(&pIterator));
            IFC_RETURN(pIterator->SetView(this));
            *first = pIterator;
            return S_OK;
        }
    };

    template <class T>
    class __declspec(novtable) PresentationFrameworkCollection:
        public IUntypedVector,
        public PresentationFrameworkCollectionTemplateBase<T>
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IVector<T>::T_complex>::type T_abi;

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        PresentationFrameworkCollection() = default;

    public:
        IFACEMETHODIMP Append(_In_opt_ T_abi item) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            BoxerBuffer buffer;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());
            IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), item, &buffer, &pMOR));

            IFC(CoreImports::Collection_Add(
                static_cast<CCollection*>(this->GetHandle()),
                &boxedValue));

        Cleanup:
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }

        IFACEMETHODIMP GetAt(UINT index, _Out_ T_abi *item) override
        {
            HRESULT hr = S_OK;
            CValue value;
            XINT32 nIndex = static_cast<XINT32>(index);

            IFC(this->CheckThread());
            IFC(CoreImports::Collection_GetItem(static_cast<CCollection*>(this->GetHandle()), nIndex, &value));
            IFC(CValueBoxer::UnboxObjectValue(&value, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), __uuidof(T_abi), reinterpret_cast<void**>(item)));

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP IndexOf(_In_opt_ T_abi value, _Out_ UINT *index, _Out_ BOOLEAN *found) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            XINT32 coreIndex = -1;
            BoxerBuffer buffer;
            *index = 0;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());

            if (value != NULL)
            {
                IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), value, &buffer, &pMOR));

                if (SUCCEEDED(CoreImports::Collection_IndexOf(
                    static_cast<CCollection*>(this->GetHandle()),
                    &boxedValue,
                    &coreIndex)))
                {
                    *index = static_cast<UINT>(coreIndex);
                }
            }

            *found = coreIndex != -1;

        Cleanup:
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }

        IFACEMETHODIMP InsertAt(UINT index, _In_opt_ T_abi item) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            BoxerBuffer buffer;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());

            UINT size = 0;
            IFC(this->get_Size(&size));
            IFCEXPECTRC(index <= size, E_BOUNDS);

            IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), item, &buffer, &pMOR));

            IFC(CoreImports::Collection_Insert(
                static_cast<CCollection*>(this->GetHandle()),
                index,
                &boxedValue));

        Cleanup:
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }

        IFACEMETHODIMP UntypedAppend(_In_ IInspectable* pItem) override
        {
            HRESULT hr = S_OK;
            T_abi pTypedItem = NULL;

            IFC(this->CheckThread());
            IFC(ctl::do_query_interface(pTypedItem, pItem));
            IFC(this->Append(pTypedItem));

        Cleanup:
            ReleaseInterface(pTypedItem);
            RRETURN(hr);
        }

        IFACEMETHODIMP UntypedGetSize(
            _Out_ unsigned int* pSize) override
        {
            IFC_RETURN(this->CheckThread());
            return this->get_Size(pSize);
        }

        IFACEMETHODIMP UntypedGetAt(
            _In_ unsigned int index,
            _COM_Outptr_ IInspectable** ppItem) override
        {
            wrl::ComPtr<typename std::remove_pointer<T_abi>::type> spTypedItem;

            *ppItem = nullptr;
            IFC_RETURN(this->CheckThread());
            IFC_RETURN(this->GetAt(index, &spTypedItem));
            IFC_RETURN(spTypedItem.CopyTo(ppItem));

            return S_OK;
        }

        IFACEMETHODIMP UntypedInsertAt(_In_ unsigned int index, _In_ IInspectable* pItem) override
        {
            wrl::ComPtr<IInspectable> spItem (pItem);
            wrl::ComPtr<typename std::remove_pointer<T_abi>::type> spTypedItem;

            IFC_RETURN(this->CheckThread());
            IFC_RETURN(spItem.As(&spTypedItem));
            IFC_RETURN(this->InsertAt(index, spTypedItem.Get()));

            return S_OK;
        }

        IFACEMETHODIMP UntypedRemoveAt(_In_ unsigned int index) override
        {
            IFC_RETURN(this->CheckThread());
            IFC_RETURN(this->RemoveAt(index));

            return S_OK;
        }

        IFACEMETHODIMP UntypedClear() override
        {
            IFC_RETURN(this->CheckThread());
            IFC_RETURN(this->Clear());

            return S_OK;
        }

    protected:
        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(IUntypedVector)))
            {
                *ppObject = static_cast<IUntypedVector*>(this);
            }
            else
            {
                RRETURN(PresentationFrameworkCollectionTemplateBase<T>::QueryInterfaceImpl(iid, ppObject));
            }

            this->AddRefOuter();
            RRETURN(S_OK);
        }
    };

    template <class T>
    class __declspec(novtable) ObservablePresentationFrameworkCollectionTemplateBase:
        public wfc::IObservableVector<T>,
        public PresentationFrameworkCollectionTemplateBase<T>
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IObservableVector<T>::T_complex>::type T_abi;

        BEGIN_INTERFACE_MAP(ObservablePresentationFrameworkCollectionTemplateBase, PresentationFrameworkCollectionTemplateBase<T>)
            INTERFACE_ENTRY(ObservablePresentationFrameworkCollectionTemplateBase, wfc::IObservableVector<T>)
        END_INTERFACE_MAP(ObservablePresentationFrameworkCollectionTemplateBase, PresentationFrameworkCollectionTemplateBase<T>)

    protected:
        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IObservableVector<T>)))
            {
                *ppObject = static_cast<wfc::IObservableVector<T> *>(this);
            }
            else
            {
                RRETURN(PresentationFrameworkCollectionTemplateBase<T>::QueryInterfaceImpl(iid, ppObject));
            }

            this->AddRefOuter();
            RRETURN(S_OK);
        }

        // This class is marked novtable, so must not be instantiated directly.
        ObservablePresentationFrameworkCollectionTemplateBase()
        {
            m_pEventSource = NULL;
        }

    public:
        typedef CEventSource<wfc::VectorChangedEventHandler<T>, wfc::IObservableVector<T>, wfc::IVectorChangedEventArgs> VectorChangedEventSourceType;

        ~ObservablePresentationFrameworkCollectionTemplateBase() override
        {
            ctl::release_interface(m_pEventSource);
        }

        void OnReferenceTrackerWalk(INT walkType) override
        {
            if( m_pEventSource != NULL )
                m_pEventSource->ReferenceTrackerWalk(static_cast<EReferenceTrackerWalkType>(walkType));

            PresentationFrameworkCollectionTemplateBase<T>::OnReferenceTrackerWalk( walkType );
        }

        IFACEMETHODIMP add_VectorChanged(_In_ wfc::VectorChangedEventHandler<T>* pHandler, _Out_ EventRegistrationToken* ptToken) override
        {
            HRESULT hr = S_OK;
            VectorChangedEventSourceType* pEventSource = NULL;

            IFC(GetVectorChangedEventSource(&pEventSource));
            IFC(pEventSource->AddHandler(pHandler));

            ptToken->value = (INT64)pHandler;

        Cleanup:
            ctl::release_interface(pEventSource);
            RRETURN(hr);
        }

        IFACEMETHODIMP remove_VectorChanged(EventRegistrationToken tToken) override
        {
            HRESULT hr = S_OK;
            VectorChangedEventSourceType* pEventSource = NULL;
            wfc::VectorChangedEventHandler<T>* pHandler = (wfc::VectorChangedEventHandler<T>*)tToken.value;

            IFC(GetVectorChangedEventSource(&pEventSource));
            IFC(pEventSource->RemoveHandler(pHandler));

            tToken.value = 0;

        Cleanup:
            ctl::release_interface(pEventSource);
            RRETURN(hr);
        }

    protected:
        _Check_return_ HRESULT GetVectorChangedEventSource(_Out_ VectorChangedEventSourceType** ppEventSource)
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());
            if (!m_pEventSource)
            {
                IFC(ctl::ComObject<VectorChangedEventSourceType>::CreateInstance(&m_pEventSource));
                m_pEventSource->Initialize(KnownEventIndex::UnknownType_UnknownEvent, this, FALSE);
            }

            *ppEventSource = m_pEventSource;
            ctl::addref_interface(m_pEventSource);

        Cleanup:
            RRETURN(hr);
        }

    private:
        VectorChangedEventSourceType* m_pEventSource;
    };

    template <class T>
    class __declspec(novtable) ObservablePresentationFrameworkCollection:
        public ObservablePresentationFrameworkCollectionTemplateBase<T>
    {
        typedef typename wf::Internal::GetAbiType<typename wfc::IVector<T>::T_complex>::type T_abi;

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ObservablePresentationFrameworkCollection() = default;

    public:
        IFACEMETHODIMP Append(_In_opt_ T_abi item) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            BoxerBuffer buffer;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());
            IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), item, &buffer, &pMOR));

            IFC(CoreImports::Collection_Add(
                static_cast<CCollection*>(this->GetHandle()),
                &boxedValue));

        Cleanup:
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }

        IFACEMETHODIMP GetAt(UINT index, _Out_ T_abi *item) override
        {
            HRESULT hr = S_OK;
            CValue value;
            XINT32 nIndex = static_cast<XINT32>(index);

            IFC(this->CheckThread());
            IFC(CoreImports::Collection_GetItem(static_cast<CCollection*>(this->GetHandle()), nIndex, &value));
            IFC(CValueBoxer::UnboxObjectValue(&value, NULL, __uuidof(T_abi), reinterpret_cast<void**>(item)));

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP IndexOf(_In_opt_ T_abi value, _Out_ UINT *index, _Out_ BOOLEAN *found) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            BoxerBuffer buffer;
            XINT32 coreIndex = -1;
            T_abi pCurrentValue = NULL;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());

            IFCPTR(index);
            IFCPTR(found);

            *index = 0;
            *found = FALSE;

            if (value != NULL)
            {
                BOOLEAN wrappingNeeded = FALSE;
                IFC(ExternalObjectReference::ShouldBeWrapped(value, wrappingNeeded));
                if (!wrappingNeeded)
                {
                    IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), value, &buffer, &pMOR));

                    if (SUCCEEDED(CoreImports::Collection_IndexOf(
                        static_cast<CCollection*>(this->GetHandle()),
                        &boxedValue,
                        &coreIndex)))
                    {
                        *index = static_cast<unsigned>(coreIndex);
                    }

                    *found = coreIndex != -1;
                }
                else
                {
                    UINT nCount = 0;
                    IFC(this->get_Size(&nCount));
                    for (UINT i = 0; i < nCount; ++i)
                    {
                        bool areEqual = false;
                        IFC(this->GetAt(i, &pCurrentValue));
                        IFC(PropertyValue::AreEqual(value, pCurrentValue, &areEqual));
                        ReleaseInterface(pCurrentValue);
                        if (areEqual)
                        {
                            *index = i;
                            *found = TRUE;
                            break;
                        }
                    }
                }
            }

        Cleanup:
            ReleaseInterface(pCurrentValue);
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }

        IFACEMETHODIMP InsertAt(UINT index, _In_opt_ T_abi item) override
        {
            HRESULT hr = S_OK;
            CValue boxedValue;
            BoxerBuffer buffer;
            DependencyObject* pMOR = NULL;

            IFC(this->CheckThread());

            UINT size = 0;
            IFC(this->get_Size(&size));
            IFCEXPECTRC(index <= size, E_BOUNDS);

            IFC(CValueBoxer::BoxObjectValue(&boxedValue, MetadataAPI::GetClassInfoByIndex(KnownTypeIndex::DependencyObject), item, &buffer, &pMOR));

            IFC(CoreImports::Collection_Insert(
                static_cast<CCollection*>(this->GetHandle()),
                index,
                &boxedValue));

        Cleanup:
            ctl::release_interface(pMOR);
            RRETURN(hr);
        }
    };

    // This exists because in codegen TextElementCollection used to be a separate
    // entity from the standard PresentationFrameworkCollection. It serves no purpose
    // otherwise.
    template <class T>
    class TextElementCollection : public PresentationFrameworkCollection<T> { };
#pragma endregion

#pragma region DO-backed Value Collection Specializations
    // These collections exist to support projection of CDoubleCollection and friends
    // into WinRT interfaces.

    template<>
    class PresentationFrameworkCollection<FLOAT> :
        public PresentationFrameworkCollectionTemplateBase<FLOAT>
    {
    public:
        // IVector<FLOAT> implementation
        IFACEMETHOD(Append)(_In_ FLOAT item) override;
        IFACEMETHOD(GetAt)(UINT index, _Out_ FLOAT *item) override;
        IFACEMETHOD(InsertAt)(UINT index, _In_ FLOAT item) override;
        IFACEMETHOD(IndexOf)(_In_ FLOAT value, _Out_ UINT *index, _Out_ BOOLEAN *found) override;
    };

    template<>
    class PresentationFrameworkCollection<DOUBLE> :
        public PresentationFrameworkCollectionTemplateBase<DOUBLE>
    {
    public:
        // IVector<DOUBLE> implementation
        IFACEMETHOD(Append)(_In_ DOUBLE item) override;
        IFACEMETHOD(GetAt)(UINT index, _Out_ DOUBLE *item) override;
        IFACEMETHOD(InsertAt)(UINT index, _In_ DOUBLE item) override;
        IFACEMETHOD(IndexOf)(_In_ DOUBLE value, _Out_ UINT *index, _Out_ BOOLEAN *found) override;
    };

    template<>
    class PresentationFrameworkCollection<wf::Point> :
        public PresentationFrameworkCollectionTemplateBase<wf::Point>
    {
    public:
        // IVector<wf::Point> implementation
        IFACEMETHOD(Append)(_In_ wf::Point item) override;
        IFACEMETHOD(GetAt)(UINT index, _Out_ wf::Point *item) override;
        IFACEMETHOD(InsertAt)(UINT index, _In_ wf::Point item) override;
        IFACEMETHOD(IndexOf)(_In_ wf::Point value, _Out_ UINT *index, _Out_ BOOLEAN *found) override;
    };

    template<>
    class PresentationFrameworkCollection<xaml_docs::TextRange> :
        public PresentationFrameworkCollectionTemplateBase<xaml_docs::TextRange>
    {
    public:
        // IVector<wf::TextRange> implementation
        IFACEMETHOD(Append)(_In_ xaml_docs::TextRange item) override;
        IFACEMETHOD(GetAt)(UINT index, _Out_ xaml_docs::TextRange *item) override;
        IFACEMETHOD(InsertAt)(UINT index, _In_ xaml_docs::TextRange item) override;
        IFACEMETHOD(IndexOf)(_In_ xaml_docs::TextRange value, _Out_ UINT *index, _Out_ BOOLEAN *found) override;
    };
#pragma endregion

#pragma region ValueType Collections
    // DEPRECATED: All of these have WRL-equivalent implementations. It's unclear why they were
    // historically used, maybe WRL collections weren't available yet, but they probably have
    // subtle differences in behavior from the official collections which means we must keep
    // them around for now until we can remove their usage sites under a quirk.
    //
    // Do not use these in new code.
    template<typename T>
    class __declspec(novtable) ValueTypeIterator :
        public IteratorBase<T>
    {
    protected:

        // This class is marked novtable, so must not be instantiated directly.
        ValueTypeIterator() = default;

        _Check_return_ HRESULT GetCurrent(_Out_ T *current) override
        {
            HRESULT hr = S_OK;

            IFCPTR(current);
            *current = m_current;

        Cleanup:
            RRETURN(hr);
        }

        void ClearCurrent() override
        {
        }

        void SetCurrent(_In_ T current) override
        {
            m_current = current;
        }

        T m_current{};
    };

    template <typename T>
    class __declspec(novtable) ValueTypeViewBase :
        public wfc::IVectorView<T>,
        public wfc::IIterable<T>,
        public ctl::WeakReferenceSource
    {
        BEGIN_INTERFACE_MAP(ValueTypeViewBase, ctl::WeakReferenceSource)
            INTERFACE_ENTRY(ValueTypeViewBase, wfc::IVectorView<T>)
            INTERFACE_ENTRY(ValueTypeViewBase, wfc::IIterable<T>)
        END_INTERFACE_MAP(ValueTypeViewBase, ctl::WeakReferenceSource)

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ValueTypeViewBase() = default;

        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IVectorView<T>)))
            {
                *ppObject = static_cast<wfc::IVectorView<T> *>(this);
            }
            else if (InlineIsEqualGUID(iid, __uuidof(wfc::IIterable<T>)))
            {
                *ppObject = static_cast<wfc::IIterable<T> *>(this);
            }
            else
            {
                RRETURN(ctl::WeakReferenceSource::QueryInterfaceImpl(iid, ppObject));
            }

            AddRefOuter();
            RRETURN(S_OK);
        }

    public:
        ~ValueTypeViewBase() override
        {
            ClearView();
        }

        virtual void ClearView()
        {
            m_vector.clear();
        }

        _Check_return_ HRESULT SetView(_In_ wfc::IIterator<T>* view)
        {
            HRESULT hr = S_OK;
            IFCPTR(view);

            ClearView();
            BOOLEAN hasCurrent = FALSE;
            IFC(view->get_HasCurrent(&hasCurrent));
            while (hasCurrent)
            {
                T item;
                IFC(view->get_Current(&item));
                m_vector.emplace_back(std::move(item));
                IFC(view->MoveNext(&hasCurrent));
            }

        Cleanup:
            RRETURN(hr);
        }

        _Check_return_ HRESULT SetView(_In_reads_opt_(cItems) const T* pItems, _In_ UINT cItems)
        {
            HRESULT hr = S_OK;

            ClearView();
            if (pItems)
            {
                m_vector.assign(pItems, pItems + cItems);
            }

            RRETURN(hr);//RRETURN_REMOVAL
        }

        // Note use of pass-by-value. std::vector knows how to rvalue move itself, so we let the caller
        // decide if they are copying from an lvalue or moving from an rvalue. Either, way, we will
        // do a fast move from the result.
        void SetView(std::vector<T> items)
        {
            m_vector = std::move(items);
        }

        IFACEMETHODIMP get_Size(_Out_ UINT *size) override
        {
            HRESULT hr = S_OK;

            IFC(CheckThread());
            *size = static_cast<UINT>(m_vector.size());

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP GetAt(UINT index, _Out_ T *item) override
        {
            HRESULT hr = S_OK;

            IFC(CheckThread());

            if (index < m_vector.size())
            {
                *item = m_vector[index];
            }
            else
            {
                IFC(E_FAIL);
            }

        Cleanup:
            RRETURN(hr);
        }

        // IIterable<T> implementation
        IFACEMETHODIMP First(_Outptr_result_maybenull_ wfc::IIterator<T> **first) override
        {
            HRESULT hr = S_OK;
            ctl::ComPtr<ValueTypeIterator<T>> spIterator;

            IFC(CheckThread());

            IFC(ctl::make(&spIterator));
            IFC(spIterator->SetView(this));
            *first = spIterator.Detach();

        Cleanup:
            RRETURN(hr);
        }

    protected:
        std::vector<T> m_vector;
    };

    template <typename T>
    class __declspec(novtable) ValueTypeView :
        public ValueTypeViewBase<T>
    {
    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ValueTypeView() = default;

    public:
        IFACEMETHODIMP IndexOf(_In_ T value, _Out_ UINT *index, _Out_ BOOLEAN *found) override
        {
            HRESULT hr = S_OK;

            *index = 0;
            *found = FALSE;

            IFC(this->CheckThread());

            {
                auto beginIterator = std::begin(this->m_vector);
                auto endIterator = std::end(this->m_vector);
                auto foundIterator = std::find(beginIterator, endIterator, value);

                if (foundIterator != endIterator)
                {
                    *index = static_cast<UINT>(foundIterator - beginIterator);
                    *found = TRUE;
                }
            }

        Cleanup:
            RRETURN(hr);
        }
    };

    template <typename T>
    class __declspec(novtable) ValueTypeCollection :
        public wfc::IVector<T>,
        public ValueTypeView<T>
    {
        BEGIN_INTERFACE_MAP(ValueTypeCollection, ValueTypeView<T>)
            INTERFACE_ENTRY(ValueTypeCollection, wfc::IVector<T>)
        END_INTERFACE_MAP(ValueTypeCollection, ValueTypeView<T>)

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ValueTypeCollection() = default;

        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IVector<T>)))
            {
                *ppObject = static_cast<wfc::IVector<T> *>(this);
            }
            else
            {
                RRETURN(ValueTypeView<T>::QueryInterfaceImpl(iid, ppObject));
            }

            this->AddRefOuter();
            RRETURN(S_OK);
        }

    public:

        IFACEMETHODIMP GetAt(UINT index, _Out_ T *item) override
        {
            RRETURN(ValueTypeView<T>::GetAt(index, item));
        }

        IFACEMETHODIMP get_Size(_Out_ UINT *size) override
        {
            RRETURN(ValueTypeView<T>::get_Size(size));
        }

        IFACEMETHODIMP GetView(_Outptr_result_maybenull_ wfc::IVectorView<T>** view) override
        {
            if (view)
            {
                RRETURN(ctl::do_query_interface(*view, this));
            }
            RRETURN(E_NOTIMPL);
        }

        IFACEMETHODIMP IndexOf(_In_ T value, _Out_ UINT *index, _Out_ BOOLEAN *found) override
        {
            RRETURN(ValueTypeView<T>::IndexOf(value, index, found));
        }

        IFACEMETHODIMP SetAt(UINT index, _In_ T item) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            // Wow! The old implementation used to clip "index" to the actual size, possibly writing
            // to one-beyond the end. This is bad bad bad. Let's fail instead of writing to random memory
            if (index < this->m_vector.size())
            {
                this->m_vector[index] = std::move(item);
            }
            else
            {
                IFC(E_FAIL);
            }

            IFC(RaiseVectorChanged(wfc::CollectionChange_ItemChanged, index));
        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP InsertAt(UINT index, _In_ T item) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            // The old std::list-based implementation used to clip "index" to the actual size
            // The old implementation also used to not wrap the allocation in an IFCSTL
            this->m_vector.insert(begin(this->m_vector) + MIN(index, this->m_vector.size()), std::move(item));

            IFC(RaiseVectorChanged(wfc::CollectionChange_ItemInserted, index));

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP RemoveAt(UINT index) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            // The old std::list-based implementation used to clip "index" to the actual size
            this->m_vector.erase(begin(this->m_vector) + MIN(index, this->m_vector.size()));

            IFC(RaiseVectorChanged(wfc::CollectionChange_ItemRemoved, index));

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP Append(_In_ T item) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            this->m_vector.emplace_back(std::move(item));
            IFC(RaiseVectorChanged(wfc::CollectionChange_ItemInserted, this->m_vector.size() - 1));

        Cleanup:
            RRETURN(hr);
        }

        IFACEMETHODIMP RemoveAtEnd() override
        {
            UINT size = this->m_vector.size();

            IFCEXPECTRC_RETURN(size > 0, E_BOUNDS);

            IFC_RETURN(RemoveAt(size - 1));

            return S_OK;
        }

        IFACEMETHODIMP Clear() override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());
            this->ClearView();
            IFC(RaiseVectorChanged(wfc::CollectionChange_Reset, 0));

        Cleanup:
            RRETURN(hr);
        }

    protected:
        virtual _Check_return_ HRESULT RaiseVectorChanged(_In_ wfc::CollectionChange action, UINT index)
        {
            RRETURN(S_OK);
        }
    };

    template <typename T>
    class __declspec(novtable) ValueTypeObservableCollection :
        public wfc::IObservableVector<T>,
        public ValueTypeCollection<T>
    {
        BEGIN_INTERFACE_MAP(ValueTypeObservableCollection, ValueTypeCollection<T>)
            INTERFACE_ENTRY(ValueTypeObservableCollection, wfc::IObservableVector<T>)
        END_INTERFACE_MAP(ValueTypeObservableCollection, ValueTypeCollection<T>)

    protected:
        // This class is marked novtable, so must not be instantiated directly.
        ValueTypeObservableCollection() = default;

        _Check_return_ HRESULT QueryInterfaceImpl(_In_ REFIID iid, _Outptr_ void** ppObject) override
        {
            if (InlineIsEqualGUID(iid, __uuidof(wfc::IObservableVector<T>)))
            {
                *ppObject = static_cast<wfc::IObservableVector<T> *>(this);
            }
            else
            {
                RRETURN(ValueTypeCollection<T>::QueryInterfaceImpl(iid, ppObject));
            }

            this->AddRefOuter();
            RRETURN(S_OK);
        }

    public:
        ~ValueTypeObservableCollection() override
        {
            ClearHandlers();
        }

        /*eventadd*/
        IFACEMETHODIMP add_VectorChanged(_In_opt_ wfc::VectorChangedEventHandler<T>* handler, _Out_ EventRegistrationToken *token) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            IFCPTR(handler);
            IFCPTR(token);

            m_handlers.push_back(handler);
            AddRefInterface(handler);
            token->value = reinterpret_cast<INT64>(handler);

        Cleanup:
            RRETURN(hr);
        }

        /*eventremove*/
        IFACEMETHODIMP remove_VectorChanged(EventRegistrationToken token) override
        {
            HRESULT hr = S_OK;

            IFC(this->CheckThread());

            for (auto it = m_handlers.begin(); it != m_handlers.end(); ++it)
            {
                if (*it == reinterpret_cast<wfc::VectorChangedEventHandler<T>*>(token.value))
                {
                    (*it)->Release();
                    m_handlers.erase(it);
                    token.value = 0;
                    goto Cleanup;
                }
            }

            IFC(E_FAIL);
        Cleanup:
            RRETURN(hr);
        }

    protected:
        _Check_return_ HRESULT RaiseVectorChanged(_In_ wfc::CollectionChange action, UINT index) override
        {
            HRESULT hr = S_OK;
            wfc::IVectorChangedEventArgs* pArgsAsI = NULL;
            VectorChangedEventArgs* pArgs = NULL;

            for (auto it = m_handlers.begin(); it != m_handlers.end(); ++it)
            {
                // Create the args
                IFC(ctl::ComObject<VectorChangedEventArgs>::CreateInstance(&pArgsAsI));
                pArgs = static_cast<VectorChangedEventArgs*>(pArgsAsI);

                IFC(pArgs->put_CollectionChange(action));
                IFC(pArgs->put_Index(index));
                IFC((*it)->Invoke(this, pArgs));
                ReleaseInterface(pArgsAsI);
            }

        Cleanup:
            ReleaseInterface(pArgsAsI);
            RRETURN(hr);
        }

    private:
        void ClearHandlers()
        {
            for (auto it = m_handlers.begin(); it != m_handlers.end(); ++it)
            {
                (*it)->Release();
            }

            m_handlers.clear();
        }

        std::list<wfc::VectorChangedEventHandler<T>*> m_handlers;
    };
#pragma endregion
}
